﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using System.Windows.Threading;
using System.Diagnostics;

using Sprites;
using JavaSubstitutes;

namespace infiniteMarioDotNet
{
    public partial class PageTest : Page
    {
        MarioComponent mario;

        public PageTest()
        {
            InitializeComponent();
        }


        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            //StartMario();			  
            //PrepForBGRenderTest();
        }


        DispatcherTimer dt = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 200) };
        private void StartMario()
        {
            dt.Tick += (sender, args) =>
                {
                    if (Art.FinishedInitializing)
                    {
                        dt.Stop();
                        mario.start(LayoutRoot);
                    }
                };

            GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
            Sonar.SonarSoundEngine engine = new Sonar.SonarSoundEngine();
            Art.init(gc, engine);
            //Art.init(gc, null);Art.init(gc, null);
            mario = new MarioComponent(320, 240);
            LayoutRoot.Children.Add(mario);

            dt.Start();
            //mario.start(LayoutRoot);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            testAnimateMario();
        }

        private void testAnimateMario()
        {
            GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
            Art.init(gc, null);

            LayoutRoot.Children.RemoveAllButType(typeof(MediaElement));

            Image img = new Image();
            LayoutRoot.Children.Add(img);
            WriteableBitmap bmp = new WriteableBitmap(32, 32);

            int i = 0;
            DispatcherTimer dt = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 150) };
            dt.Tick += (senderDT, args) =>
            {
                bmp.Clear();

                bmp.Render(Art.fireMario[i, 0], null);
                bmp.Invalidate();
                img.Source = bmp;

                i++;
                if (i >= Art.fireMario.Length) i = 0;
            };

            dt.Start();

            //MessageBoy.Show("done");
        }


        private void testMoveMario()
        {
            GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
            Art.init(gc, null);

            LayoutRoot.Children.RemoveAllButType(typeof(MediaElement));

            Image img = new Image();
            LayoutRoot.Children.Add(img);
            WriteableBitmap bmp = new WriteableBitmap(32, 32);

            bmp.Clear();
            bmp.Render(Art.fireMario[2, 0], null);


            int i = 0;
            DispatcherTimer dt = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 500) };
            dt.Tick += (senderDT, args) =>
            {
                bmp.copyAndMoveArea(0, 0, 32, 32, 2, 2);
                bmp.Invalidate();
                img.Source = bmp;

                i++;
                if (i >= 15)
                {
                    i = 0;
                    MessageBox.Show("done");
                }
            };

            dt.Start();


        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            testMoveMario();

        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
            Sonar.SonarSoundEngine engine = new Sonar.SonarSoundEngine();
            Art.init(gc, engine);

            LayoutRoot.Children.RemoveAllButType(typeof(MediaElement));

            Image img = new Image();
            LayoutRoot.Children.Add(img);
            WriteableBitmap bmp = new WriteableBitmap(320, 240);

            bmp.Clear();
            //wbmp.Render(Art.fireMario[2, 0], null);

            LevelScene.renderBlackout(bmp, 0, 0, 16);
            bmp.Invalidate();
            img.Source = bmp;
        }

        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            StartMario();

        }

        private void Button_Click_4(object sender, RoutedEventArgs e)
        {
            GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
            Art.init(gc, null);

            Dispatcher.BeginInvoke(() =>
                {
                    LayoutRoot.Children.RemoveAllButType(typeof(MediaElement));

                    Image img = new Image();
                    LayoutRoot.Children.Add(img);
                    WriteableBitmap bmp = new WriteableBitmap(8 * 32, 10 * 32); //32py tiles 8,10

                    int i = 0;

                    for (int y = 0; y < 10; y++)
                        for (int x = 0; x < 8; x++)
                        {
                            //wbmp.Render(Art.bg[destX, destY], null);
                            bmp.drawImage(Art.bg[x, y], x * 32, y * 32);
                            bmp.Invalidate(); //after every  time?
                        }

                    bmp.Invalidate();
                    img.Source = bmp;

                });
        }

        private void clickInitArt(object sender, RoutedEventArgs e)
        {
            GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
            Art.init(gc, null);
        }

        private void LayoutRoot_KeyDown(object sender, KeyEventArgs e)
        {
            if (mario == null)
            {
                //for testing the level scrolling
                if (e.Key == Key.Left)
                    MoveRightBG();

                if (e.Key == Key.Right)
                    MoveLeftBG();

                return;
            }

            mario.toggleKey(e.Key, true);
        }

        private void LayoutRoot_KeyUp(object sender, KeyEventArgs e)
        {
            if (mario == null) return;

            mario.toggleKey(e.Key, false);
        }

        private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (mario == null) return;
            mario.ShowStartGameScene();
        }

        private void Button_Click_5(object sender, RoutedEventArgs e)
        {
            //test.Position = new TimeSpan();
            //test.Play();
        }

        private void test_MediaOpened(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("got sound");
        }

        private void test_MediaFailed(object sender, ExceptionRoutedEventArgs e)
        {
            MessageBox.Show("media failed");
        }

        private void btnFlip_Click(object sender, RoutedEventArgs e)
        {
            //WriteableBitmap bmp = new WriteableBitmap((int)imgTest.ActualWidth, (int)imgTest.ActualHeight);
            //drawImage(bmp, imgTest, 0, 0, null);

        }


        //test
        public void drawImage(WriteableBitmap dest, Image sourceImg, double destX, double destY, Transform transform)
        {
            //consider: is this any better than simply calling bmp.Render  with translate xform? That seemed to work alright.
            dest.Invalidate();

            WriteableBitmap bmpImg = new WriteableBitmap((int)sourceImg.ActualWidth, (int)sourceImg.ActualHeight);
            bmpImg.Render(sourceImg, transform);
            bmpImg.Invalidate();
            FlipHorizontal(bmpImg);

            dest.Blit(
                new Rect(destX, destY, sourceImg.ActualWidth, sourceImg.ActualHeight),  //dest rect 
                bmpImg,  //to blit to the dest wbmp
                new Rect(0, 0, sourceImg.ActualWidth, sourceImg.ActualHeight)); //source

            dest.Invalidate();

            ///imgTest.Source = bmpImg;
        }

        public void FlipHorizontal(WriteableBitmap wbmp)
        {
            //CANNOT get the scaletransform to render when the scale value's negative, so until that's sorted out
            //we'll do it by hand
            int width = wbmp.PixelWidth, height = wbmp.PixelHeight; //after examining the IL-cache the values so the CLR doesn't call them as much

            for (int y = 0; y < height; y++)
                for (int x = 0; x < width / 2; x++)
                {
                    int lhsPixel = wbmp.Pixels[(y * width) + x];
                    wbmp.Pixels[(y * width) + x] = wbmp.Pixels[(y * width) + (width - x - 1)]; //assign the RHS pixel to the LHS pixel
                    wbmp.Pixels[(y * width) + (width - x - 1)] = lhsPixel;
                }
        }

        private void imgTest_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {

            Debug.WriteLine("failed");
        }

        BgRenderer bgLayer0 = null;
        WriteableBitmap wbmp = new WriteableBitmap(320, 240);
        Image img = new Image();
        private void btnRenderBG_Click(object sender, RoutedEventArgs e)
        {
            PrepForBGRenderTest();
        }

        private void PrepForBGRenderTest()
        {
            dt.Tick += (sender2, args) =>
            {
                if (Art.FinishedInitializing)
                {
                    dt.Stop();
                    LayoutRoot.Children.Clear();
                    LayoutRoot.Children.Add(img);

                    x = 160;
                    bgLayer0.setCam(0, 0);
                    //bgLayer0.render(wbmp, x, 0);

                    btnRight.Visibility = btnLeft.Visibility = Visibility.Visible;
                }
            };

            GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
            Sonar.SonarSoundEngine engine = new Sonar.SonarSoundEngine();
            Art.init(gc, engine);

            bgLayer0 = new BgRenderer(BgLevelGenerator.createLevel(2048, 15, false, LevelGenerator.TYPE_OVERGROUND), gc, 320, 240, 2);
            img.Source = wbmp;
            LayoutRoot.Children.Add(img);

            dt.Start();
        }


		//setup to let you scroll the BG layer
		private void PrepForBGRenderTestWithImages()
		{
			dt.Tick += (sender2, args) =>
			{
				if (Art.FinishedInitializing)
				{
					dt.Stop();
					LayoutRoot.Children.Clear();
					LayoutRoot.Children.Add(img);

					x = 160;
					bgLayer0.setCam(0, 0);
					//bgLayer0.render(wbmp, x, 0);

					MessageBox.Show("go for it");
				}
			};

			GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
			Sonar.SonarSoundEngine engine = new Sonar.SonarSoundEngine();
			Art.init(gc, engine);

			bgLayer0 = new BgRenderer(BgLevelGenerator.createLevel(2048, 15, false, LevelGenerator.TYPE_OVERGROUND), gc, 320, 240, 2);
			//img.Source = wbmp;
			//LayoutRoot.Children.Add(img);


			dt.Start();
		}

		LevelRenderer fgLayer = null;
		//setup to let you scroll the FG layer
		private void PrepForFGRenderTestWithImages()
		{
			dt.Tick += (sender2, args) =>
			{
				if (Art.FinishedInitializing)
				{
					dt.Stop();
					LayoutRoot.Children.Clear();
					LayoutRoot.Children.Add(img);

					x = 160;
					fgLayer.setCam(wbmp,0, 0);
					fgLayer.render(wbmp, x, 0);

					MessageBox.Show("go for it");
				}
			};

			GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
			Sonar.SonarSoundEngine engine = new Sonar.SonarSoundEngine();
			Art.init(gc, engine);

			fgLayer = new LevelRenderer(LevelGenerator.createLevel(2048, 15, 0, 1, LevelGenerator.TYPE_OVERGROUND), gc, 320, 240);
			//img.Source = wbmp;
			//LayoutRoot.Children.Add(img);


			dt.Start();
		}


        int x = 0;
        private void btnLeft_Click(object sender, RoutedEventArgs e)
        {
            MoveLeftBG();
        }

        private void MoveRightBG()
        {
            if (x <= 0) return;
            x--;
            RenderBackground(x);
        }

        private void btnRight_Click(object sender, RoutedEventArgs e)
        {
            MoveRightBG();
        }

        private void MoveLeftBG()
        {
            if (x <= 0) return;
            x++;
            RenderBackground(x);
        }

        private void RenderBackground(int x)
        {
            bgLayer0.setCam(x, 0);
            bgLayer0.render(wbmp, x, 0);
            wbmp.Invalidate();
            img.Source = wbmp;
        }

        private void btnClear_Click(object sender, RoutedEventArgs e)
        {
            wbmp.Clear();
            img.Source = wbmp;
        }

        private void btnStartMario_Click(object sender, RoutedEventArgs e)
        {
            StartMario();
        }

        private void btnStartBGRenderTest_Click(object sender, RoutedEventArgs e)
        {
            SetupMarioBGRenderTest();
        }

        private void SetupMarioBGRenderTest()
        {

            dt.Tick += (sender, args) =>
            {
                if (Art.FinishedInitializing)
                {
                    dt.Stop();
                    mario.start(LayoutRoot);
                    //mario.Dispatcher.BeginInvoke(()=>
                    //    mario.startLevel(RandomExtensions.nextInt(), 0, LevelGenerator.TYPE_OVERGROUND));
                };
            };

            GraphicsConfiguration gc = new GraphicsConfiguration(LayoutRoot);
            Sonar.SonarSoundEngine engine = new Sonar.SonarSoundEngine();
            Art.init(gc, engine);
            //Art.init(gc, null);Art.init(gc, null);
            mario = new MarioComponent(320, 240);
            LayoutRoot.Children.Add(mario);

            dt.Start();
            //mario.start(LayoutRoot);
        
        }

		private void btnTryBGLayout_Click(object sender, RoutedEventArgs e)
		{
			//PrepForBGRenderTestWithImages(); //meliot this works now
			PrepForFGRenderTestWithImages();
		}


		int CameraX = 0, CameraY = 0;
		public void updateAreaForBGLayer(int x0, int y0, int w, int h)
		{
			if (Art.bg == null) return; //hasn't loaded yet

			canvasBG.Children.Clear();
			//wBGbmp.clearRect(x0, y0, w, h); //original
			
			int xTileStart = (x0 + CameraX) / 32;
			int yTileStart = (y0 + CameraY) / 32;
			int xTileEnd = (x0 + CameraX + w) / 32;
			int yTileEnd = (y0 + CameraY + h) / 32;
			for (int x = xTileStart; x <= xTileEnd; x++)
			{
				for (int y = yTileStart; y <= yTileEnd; y++)
				{					
					//int b = Level.getBlock(x, y) & 0xff;
					int b = bgLayer0.Level.getBlock(x, y) & 0xff;
					//wBGbmp.drawImage(Art.bg[b % 8, b / 8], (x << 5) - CameraX, (y << 5) - CameraY - 16);

					Image img = new Image() { Source = new BitmapImage(((BitmapImage)Art.bg[b % 8, b / 8].Source).UriSource) { CreateOptions = BitmapCreateOptions.None } };
					canvasBG.Children.Add(img);
					Canvas.SetLeft(img, (x << 5) - CameraX);
					Canvas.SetTop(img, (y << 5) - CameraY - 16);
			
				}
			}
		}

		private void btnLeft2_Click(object sender, RoutedEventArgs e)
		{
			updateAreaForBGLayer(100, 100, 320, 240);
			//CameraX--;
			CameraX -= 2; 
		}

		private void btnRight2_Click(object sender, RoutedEventArgs e)
		{
			updateAreaForBGLayer(100, 100, 320, 240);
			//CameraX++;
			CameraX+=2;
		}

		private void btnLeft2_Click_FG(object sender, RoutedEventArgs e)
		{
			CameraX -= 2;
			updateAreaFG(canvasBG, 100, 100, 320, 240);
		}

		private void btnRight2_Click_FG(object sender, RoutedEventArgs e)
		{
			CameraX += 2;
			updateAreaFG(canvasBG, 100, 100, 320, 240);			
		}

		//public void updateAreaFG(WriteableBitmap wbmp, int x0, int y0, int w, int h)
		public void updateAreaFG(Canvas canvas, int x0, int y0, int w, int h)
		{
			canvas.Children.Clear();

			int xTileStart = (x0 + CameraX) / 16;
			int yTileStart = (y0 + CameraY) / 16;
			int xTileEnd = (x0 + CameraX + w) / 16;
			int yTileEnd = (y0 + CameraY + h) / 16;
			for (int x = xTileStart; x <= xTileEnd; x++)
			{
				for (int y = yTileStart; y <= yTileEnd; y++)
				{
					int b = fgLayer.level.getBlock(x, y) & 0xff;
					if (((Level.TILE_BEHAVIORS[b]) & Level.BIT_ANIMATED) == 0)
					{
						//wbmp.drawImage(Art.level[b % 16, b / 16], (x << 4) - CameraX, (y << 4) - CameraY);
						//Image img = Art.level[b % 16, b / 16];
						Image img = new Image() { Source = new BitmapImage(((BitmapImage)Art.level[b % 16, b / 16].Source).UriSource) { CreateOptions = BitmapCreateOptions.None } };
						Canvas.SetLeft(img, (x << 4) - CameraX);
						Canvas.SetTop(img,(y << 4) - CameraY);
						canvas.Children.Add(img);
					}
				}
			}
		}

		private void btnTryDrawClick(object sender, RoutedEventArgs e)
		{
			//WriteableBitmap bmp = new WriteableBitmap(canvasBG, null);
			/*
			WriteableBitmap bmp = new WriteableBitmap((int)canvasBG.Width, (int)canvasBG.Height);
			bmp.Render(canvasBG, null);

			Canvas c = new Canvas() { Width = canvasBG.Width, Height = canvasBG.Height };
			Canvas.SetLeft(bmp, 100);
			canvasBG.Children.Add(c);

				*/

			//WriteableBitmap bmp = new WriteableBitmap((int)canvasBG.Width, (int)canvasBG.Height);
			//bmp.Render(canvasBG, null);

			//WriteableBitmap bmp2 = new WriteableBitmap((int)canvasBG.Width, (int)canvasBG.Height);
			//bmp2.Render




			

		}




    }
}

